package com.itheima.service.impl;

import com.itheima.aop.Mylog;
import com.itheima.mapper.DeptMapper;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.Dept;
import com.itheima.pojo.DeptLog;
import com.itheima.service.DeptLogService;
import com.itheima.service.DeptService;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;   //三层架构记住了，接着调用mapper

    @Autowired
    private EmpMapper empMapper;     //调用EmpMapper的方法

    @Autowired
    private DeptLogService deptLogService;

    @Mylog//自定义注解（表示：当前方法属于目标方法）。在业务类要做为连接点的方法上添加自定义注解
    @Override
    public List<Dept> list() {
        List<Dept> deptList = deptMapper.list();
        return deptList;
    }


    /**
     * @Transactional作用：就是在当前这个方法执行开始之前来开启事务，方法执行完毕之后提交事务。如果在这个方法执行的过程当中出现了异常，就会进行事务的回滚操作。
     *
     * @Transactional注解：我们一般会在业务层当中来控制事务，因为在业务层当中，一个业务功能可能会包含多个数据访问的操作。在业务层来控制事务，我们就可以将多个数据访问操作控制在一个事务范围内。
     *
     * rollbackFor这个属性可以指定出现何种异常类型回滚事务。
     *
     * 结论：- 在Spring的事务管理中，默认只有运行时异常 RuntimeException才会回滚。
     * - 如果还需要回滚指定类型的异常，可以通过rollbackFor属性来指定
     * @param id
     */


//    @Transactional  //当前方法添加了事务管理,spring事务管理
    @Transactional(rollbackFor=Exception.class)
    @Override
    public void delete(Integer id) throws Exception{
        try {
            deptMapper.deleteById(id);    //根据id删除部门数据

            //int i = 1/0;        //加上这行，会报异常，下面的语句不再执行，所以部门删了，部门下的员工没有删除造成了数据的不一致

            //模拟：异常发生
            if (true) {
                throw new Exception("出现异常了~~~");
            }   //结论：发生了Exception异常，但事务依然提交了
            //通过以上测试可以得出一个结论：默认情况下，只有出现RuntimeException(运行时异常)才会回滚事务。

            empMapper.deleteByDeptId(id);   //根据部门的id，删除该部门下的员工。
        }finally {
            /**
             * 解散部门是一个非常重要而且非常危险的操作，所以在业务当中要求每一次执行解散部门的操作都需要留下痕迹，就是要记录操作日志。而且还要求无论是执行成功了还是执行失败了，都需要留下痕迹。
             * 1. 执行解散部门的业务：先删除部门，再删除部门下的员工（前面已实现）
             * 2. 记录解散部门的日志，到日志表（未实现）
             */
            //不论是否有异常，最终都要执行的代码：记录日志。所以要放在finally代码块
            DeptLog deptLog = new DeptLog();
            deptLog.setCreateTime(LocalDateTime.now());   //操作时间为当前时间
            deptLog.setDescription("执行了解散部门的操作，此时解散的是" + id + "号部门");   //记录日志的描述信息
            //调用其他业务类中的方法
            //结果：Participating in existing transaction(参与现有的事务)，initiation transaction rollback（事务回滚）。分析：insert方法也添加了@Transactional，所以爆出异常后会一起回滚，因为只有一个事物
            //为了执行insert方法插入信息到数据库，insert方法应该建立新的事物（REQUIRES_NEW ），不被影响。在DeptLogServiceImpl类中insert方法上，添加@Transactional(propagation = Propagation.REQUIRES_NEW)
            deptLogService.insert(deptLog);
        }

    }


    @Override
    public void add(Dept dept) {
        //补全，加两个时间
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());

        //调用dao层的方法
        deptMapper.inser(dept);
    }

    @Override
    public Dept getById(Integer id) {
        Dept dept=deptMapper.getByID(id);
        return dept;
    }

    @Override
    public void update(Dept dept) {
        //更改部门名称的最后操作时间
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.update(dept);
    }


}
